﻿#include <cstdint>
#include <QtCore>
#include <QtGui/QImageReader>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

namespace helper {
bool SaveContent2File(const QByteArray& data, const QString& path, bool enable_log);
}

namespace {
//值是多少自己算。https://blog.csdn.net/weixin_30618985/article/details/96313053
constexpr uint8_t jpgA = 0xFF;  // jpeg
constexpr uint8_t jpgB = 0xD8;
constexpr uint8_t gifA = 0x47;  // gif
constexpr uint8_t gifB = 0x49;
constexpr uint8_t pngA = 0x89;  // png
constexpr uint8_t pngB = 0x50;
constexpr uint8_t webA = 0x52;  // webp
constexpr uint8_t webB = 0x49;

bool isImageJpeg(uint8_t first, uint8_t second) {
  return first == jpgA && second == jpgB;
}
bool isImageGif(uint8_t first, uint8_t second) {
  return first == gifA && second == gifB;
}
bool isImagePng(uint8_t first, uint8_t second) {
  return first == pngA && second == pngB;
}
bool isImageWebp(uint8_t first, uint8_t second) {
  return first == webA && second == webB;
}

QString findMatchImageSuffix(uchar firstV, uchar nextV) {
  if (isImageJpeg(firstV, nextV)) {
    return ".jpg";
  } else if (isImageGif(firstV, nextV)) {
    return ".gif";
  } else if (isImagePng(firstV, nextV)) {
    return ".png";
  } else if (isImageWebp(firstV, nextV)) {
    return ".webp";
  }
  return QString();
}

QByteArray downloadTargetUrl(const QString& link) {
  QByteArray                   bytes;
  static QNetworkAccessManager netWorker;
  QEventLoop                   eventLoop;
  QObject::connect(
      &netWorker, &QNetworkAccessManager::finished, &eventLoop, [&](QNetworkReply* reply) {
        if (reply->error() != QNetworkReply::NoError) {
          qWarning() << "download url " << link << " failed, " << reply->errorString();
        } else {
          bytes = reply->readAll();
        }
        reply->deleteLater();
        eventLoop.quit();
      });

  // 开启 SSL 支持 https
  auto mQSSLConfig(QSslConfiguration::defaultConfiguration());
  mQSSLConfig.setProtocol(QSsl::TlsV1_2);
  mQSSLConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
  // 支持 https， 支持 302 自动跳转
  QNetworkRequest request;
  request.setSslConfiguration(mQSSLConfig);
  request.setUrl(QUrl(link));
  netWorker.get(request);

  eventLoop.exec();
  return bytes;
}

}  // namespace

namespace helper {
// R"(E:\Workspace\Rison\GenerateWeChatMsgFromPC\wechat\source\Data\7031503036690990550.dat)"
// R"(E:\Workspace\Rison\GenerateWeChatMsgFromPC\wechat\1234.webp)"
void FindoutEncodeImageFormat(const QString& input, const QString& output) {
  QFile srcFile(input);
  srcFile.open(QIODevice::ReadOnly);
  auto&& bytes = srcFile.readAll();

  for (int i = 0; i < 256; i++) {
    for (int j = 0; j < 30; j++) {
      char res = bytes[j] ^ i;
      if ((res >= 'A' && res <= 'Z') || (res >= 'a' && res <= 'z') || (res >= '0' && res <= '9'))
        printf("%c", res);
      else
        printf(" ");
    }
    printf(".\t%02X\n", i);
  }

  //找出来的可能的格式是webp
  for (auto& b : bytes) {
    b ^= 05;
  }

  helper::SaveContent2File(bytes, output, true);
}

bool DecodeWechatImage(QString src_path, QString& dst_path) {
  Q_ASSERT(!src_path.isEmpty() && !dst_path.isEmpty());

  QFile srcFile(src_path);
  if (!srcFile.open(QIODevice::ReadOnly)) {
    qWarning() << "image open fail, " << src_path << ", " << srcFile.errorString();
    return false;
  }

  QByteArray bytes = srcFile.readAll();
  srcFile.close();

  uchar   firstV = bytes[0];
  uchar   nextV  = bytes[1];
  QString suffix = findMatchImageSuffix(firstV, nextV);
  if (suffix.isEmpty()) {
    //取反异或识别出头, https://blog.csdn.net/chrunlee/article/details/121238460
    auto jT = firstV ^ jpgA;
    auto jB = nextV ^ jpgB;

    auto gT = firstV ^ gifA;
    auto gB = nextV ^ gifB;

    auto pT = firstV ^ pngA;
    auto pB = nextV ^ pngB;

    auto wT = firstV ^ webA;
    auto wB = nextV ^ webB;

    uint8_t xorKey;  // = firstV ^ base;
    if (jT == jB) {
      xorKey = jT;
      suffix = ".jpg";
    } else if (gT == gB) {
      xorKey = gT;
      suffix = ".gif";
    } else if (pT == pB) {
      xorKey = pT;
      suffix = ".png";
    } else if (wT == wB) {
      xorKey = wT;
      suffix = ".webp";
    } else {
      qWarning() << "decode image fail, " << src_path;
      return false;
    }

    //异或处理数据，还原图片
    for (auto& byt : bytes) {
      byt ^= xorKey;
    }
  }

  //拼接后缀名
  dst_path += suffix;

  //保存到指定路径
  if (!helper::SaveContent2File(bytes, dst_path, false)) {
    qWarning() << "save decode image failed, target dir " << dst_path;
    dst_path.chop(4);  //移除后缀名
    return false;
  }
  return true;
}

bool DownloadWechatImage(const QString& link, QString& dst_path) {
  Q_ASSERT(!dst_path.isEmpty());

  auto bytes = downloadTargetUrl(link);
  if (bytes.isEmpty()) {
    return false;
  } else {
    uchar   firstV = bytes[0];
    uchar   nextV  = bytes[1];
    QString suffix = findMatchImageSuffix(firstV, nextV);
    if (suffix.isEmpty()) {
      qWarning() << "unknown image format " << bytes;
      return false;
    }

    //拼接后缀名
    dst_path += suffix;

    //保存到指定目录
    if (!helper::SaveContent2File(bytes, dst_path, false)) {
      qInfo() << "save download image failed, target dir " << dst_path;
      dst_path.chop(4);  //移除后缀名
      return false;
    }
  }
  return true;
}

QSize GetImageSize(const QString& path) {
  // 获取图片像素宽高
  QImageReader reader(path);
  auto         size = reader.size();
  return size;
}

}  // namespace helper
